package com.wb3.meta.api.core.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wb3.meta.api.core.dao.ToysMapper;
import com.wb3.meta.api.core.dao.ToysWorldMapper;
import com.wb3.meta.api.core.model.MyToys;
import com.wb3.meta.api.core.model.ToysWorld;
import com.wb3.meta.api.core.service.*;
import com.wb3.meta.api.core.vo.*;
import com.wb3.meta.common.authentication.RequestHolder;
import com.wb3.meta.common.enums.EnumConstants;
import com.wb3.meta.common.mybatis.DataTableUtil;
import com.wb3.meta.common.pojo.ResultT;
import com.wb3.meta.config.utils.RedisUtils;
import com.wb3.meta.config.utils.TTSUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.*;

@Slf4j
@Service("toysWorldService")
@Transactional(transactionManager = "dataSourceTransactionManagerOne", rollbackFor = Exception.class)
public class ToysWorldServiceImpl implements ToysWorldService {
    @Autowired
    private ToysWorldMapper toysWorldMapper;
    @Autowired
    private TTSUtils ttsUtils;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private MyToysService myToysService;
    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ToysMapper toysMapper;

    @Autowired
    private WorldInfoService worldInfoService;

    @Autowired
    private PrizeInfoService prizeInfoService;

    @Autowired
    private WinningRecordService winningRecordService;

    /**
     * 分页查询方法
     *
     * @param vo
     * @return
     */
    @Override
    public Page<ResToysWorldVo> getModelPage(ReqToysWorldVo vo) {

        PageHelper.startPage(vo.getPageNum(), vo.getPageSize());

        return (Page<ResToysWorldVo>) getModelListByConditions(vo);
    }

    /**
     * 列表查询方法 -返回 res 对象
     *
     * @param vo
     * @return
     */
    @Override
    public List<ResToysWorldVo> getModelListByConditions(ReqToysWorldVo vo) {
        return toysWorldMapper.getModelListByConditions(vo);
    }

    /**
     * 根据条件查询单条数据方法，返回res vo类
     *
     * @param vo
     * @return
     */
    @Override
    public ResToysWorldVo getResModelByConditions(ReqToysWorldVo vo) {
        return toysWorldMapper.getResModelByConditions(vo);
    }

    /**
     * 根据条件查询单个对象方法
     *
     * @param toysWorld
     * @return
     */
    @Override
    public ToysWorld getModelByConditions(ToysWorld toysWorld) {
        return null;
    }

    /**
     * 根据id查询单个对象方法
     *
     * @param id
     * @return
     */
    @Override
    public ToysWorld getModelById(Object id) {
        return toysWorldMapper.selectByPrimaryKey(id);
    }

    /**
     * 新增对象方法
     *
     * @param toysWorld
     */
    @Override
    public void addModel(ToysWorld toysWorld) {
        toysWorld.setCreateTime(new Date().getTime());
        toysWorld.setStatus(EnumConstants.StatusEnum.VALID.getCode());
        toysWorldMapper.insertUseGeneratedKeys(toysWorld);
    }

    /**
     * 更新对象方法
     *
     * @param toysWorld
     */
    @Override
    public void updateModel(ToysWorld toysWorld) {
        toysWorld.setUpdateTime(new Date().getTime());
        toysWorldMapper.updateByPrimaryKeySelective(toysWorld);
    }

    /**
     * 根据id删除对象方法
     *
     * @param id
     */
    @Override
    public void deleteModelById(Object id) {

    }

    /**
     * 获取分页数据，返回 map对象方法
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT getModelMapPage(ReqToysWorldVo vo) {
        return ResultT.success(DataTableUtil.changePage(getModelPage(vo)));
    }

    /**
     * 根据id查询单个对象方法，返回 map对象方法
     *
     * @param id
     * @return
     */
    @Override
    public ResultT getModelMapById(Object id) {
        if (id == null) {
            return ResultT.fail("id不能为空");
        }
        return null;
    }

    /**
     * 根据条件查询单个对象，返回map对象方法
     *
     * @param toysWorld
     * @return
     */
    @Override
    public ResultT getModelMapByConditions(ToysWorld toysWorld) {
        return null;
    }

    /**
     * 查询列表-map对象
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT getResModelListMapByConditions(ReqToysWorldVo vo) {
        return ResultT.success(toysWorldMapper.getModelListByConditions(vo));
    }

    /**
     * 根据条件查询res vo对象，返回map对象方法
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT getResModelMapByConditions(ReqToysWorldVo vo) {
        if (vo.getWorldId() == null) {
            return ResultT.fail("世界id不能为空");
        }
        if (vo.getToysId() == null) {
            return ResultT.fail(" 崽崽Id不能为空");
        }
        ResToysWorldVo toysWorldVo = toysWorldMapper.getResModelByConditions(vo);
        if (toysWorldVo == null) {
            //创建一个新的崽崽世界
            saveOrUpdate(vo);
//            BeanUtils.copyProperties(toysWorldVo, vo);
            toysWorldVo = toysWorldMapper.getResModelByConditions(vo);
        }

        String worldPrefix = "world-Store" + ":" + toysWorldVo.getWorldAiId() + ":" + toysWorldVo.getTextChatId();
        String lastEventKey = worldPrefix + ":" + "lastEvent:" + RequestHolder.getUserId();

        String tempData = (String) redisUtils.get(lastEventKey);
        //之前的事件还存在，存进去
        if (StringUtils.isNotBlank(tempData)) {
            toysWorldVo.setLastEvent(parseEvent(tempData));
        }


        return ResultT.success(toysWorldVo);
    }

    /**
     * 更新或插入对象方法
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT saveOrUpdate(ReqToysWorldVo vo) {
        if (vo.getId() != null) {
            updateModel(vo);
        } else {
            addModel(vo);
        }
        return ResultT.success(vo);
    }

    /**
     * 根据条件删除方法
     *
     * @param vo
     * @return
     */
    @Override
    public ResultT delete(ReqToysWorldVo vo) {
        return null;
    }


    @Override
    public ResultT getWorldEvent(ReqToysWorldVo reqToysWorldVo) throws IOException {
        if (StringUtils.isBlank(reqToysWorldVo.getWorldAiId())) {
            return ResultT.fail("世界id不能为空");
        }
        if (reqToysWorldVo.getToysId() == null) {
            return ResultT.fail("崽崽Id不能为空");
        }
        if (reqToysWorldVo.getAudioId() == null) {
            return ResultT.fail("崽崽角色Id不能为空");
        }
        ReqMyToysVo reqMyToysVo = new ReqMyToysVo();
        reqMyToysVo.setId(reqToysWorldVo.getToysId());
        reqMyToysVo.setUserId(RequestHolder.getUserId());

        ResMyToysVo resMyToysVo = myToysService.getResModelByConditions(reqMyToysVo);

        if (resMyToysVo == null) {
            return ResultT.fail("崽崽不存在");
        }

        if (resMyToysVo.getPower() < 5) {
            return ResultT.fail("崽崽体力不足");
        }

        String worldPrefix = "world-Store" + ":" + reqToysWorldVo.getWorldAiId() + ":" + reqToysWorldVo.getAudioId();
        String worldEventKey = worldPrefix +":event";
        String lastEventKey = worldPrefix + ":" + "lastEvent:" + RequestHolder.getUserId();
        String countDownEventKey = worldPrefix + ":" + "countDownEvent:" + RequestHolder.getUserId();

        Long countDownEvent = (Long) redisUtils.get(countDownEventKey);
        if (countDownEvent != null) {
            return ResultT.fail("探索冷却时间未到",countDownEvent);
        }


        Set<String> keys = redisUtils.getKeysByPrefix(worldEventKey);
        List<TTSUtils.Event> events = new ArrayList<>();
        if (keys != null) {
            keys.forEach(s -> {
                String temp = (String) redisUtils.get(s);
                if (StringUtils.isNotBlank(temp)) {
                    TTSUtils.Event event = parseEvent(temp);

                    events.add(event);
                }
            });
        }
        if (events.size() < 10) {
            ToysWorldServiceImpl proxy = applicationContext.getBean(ToysWorldServiceImpl.class);
            proxy.createAndExecuteTask(reqToysWorldVo.getWorldAiId(), reqToysWorldVo.getAudioId(), worldEventKey);
        }
        if (events.size() > 0) {
            // Generate a random number between 0 and events.size() - 1
            Random random = new Random();
            int maxIndex = events.size() - 1;
            int randomIndex = random.nextInt(maxIndex + 1); // nextInt(bound) generates a number from 0 (inclusive) to bound (exclusive)
//            log.info("----events.size()-----------{}", events.size());
//            log.info("randomIndex---------------{}", randomIndex);

            resMyToysVo.setPower(resMyToysVo.getPower() - 5);
            myToysService.updateModel(resMyToysVo);
            redisUtils.set(lastEventKey, JSONObject.toJSONString(events.get(randomIndex)));

            redisUtils.set(countDownEventKey, new Date().getTime(), 60 * 60 );

            return ResultT.success(events.get(randomIndex));
        }


        TTSUtils.Event store = ttsUtils.getStoreByWorldIdAndToysAudioId(reqToysWorldVo.getAudioId(), reqToysWorldVo.getWorldAiId());
        if (store != null) {
            redisUtils.set(worldEventKey + new Date().getTime(), JSONObject.toJSONString(store), 60 * 60 * 24);

            redisUtils.set(countDownEventKey, new Date().getTime(), 60 * 60 );

            resMyToysVo.setPower(resMyToysVo.getPower() - 5);
            myToysService.updateModel(resMyToysVo);
            redisUtils.set(lastEventKey, JSONObject.toJSONString(store));
            return ResultT.success(store);
        }


        return ResultT.fail();
    }

    @Override
    public ResultT eventChoose(ReqToysWorldVo reqToysWorldVo) {
        if (StringUtils.isBlank(reqToysWorldVo.getWorldAiId())) {
            return ResultT.fail("世界id不能为空");
        }
        if (reqToysWorldVo.getToysId() == null) {
            return ResultT.fail("崽崽Id不能为空");
        }
        if (reqToysWorldVo.getAudioId() == null) {
            return ResultT.fail("崽崽角色Id不能为空");
        }
        if (reqToysWorldVo.getEventIndex() == null || reqToysWorldVo.getEventIndex() < 0 || reqToysWorldVo.getEventIndex() > 2) {
            return ResultT.fail("事件选择不正确");
        }
        ReqMyToysVo reqMyToysVo = new ReqMyToysVo();
        reqMyToysVo.setId(reqToysWorldVo.getToysId());
        reqMyToysVo.setUserId(RequestHolder.getUserId());

        ResMyToysVo resMyToysVo = myToysService.getResModelByConditions(reqMyToysVo);

        if (resMyToysVo == null) {
            return ResultT.fail("崽崽不存在");
        }
        String worldPrefix = "world-Store" + ":" + reqToysWorldVo.getWorldAiId() + ":" + reqToysWorldVo.getAudioId();
        String lastEventKey = worldPrefix + ":" + "lastEvent:" + RequestHolder.getUserId();

        String tempData = (String) redisUtils.get(lastEventKey);
        if (StringUtils.isBlank(tempData)) {
            return ResultT.fail("事件不存在");
        }
        TTSUtils.Event event = parseEvent(tempData);
        TTSUtils.Action action = event.getActions_list().get(reqToysWorldVo.getEventIndex());

        if(resMyToysVo.getMood() + action.getFavorability() > 100){
            resMyToysVo.setMood(100);
        }else{
            resMyToysVo.setMood(resMyToysVo.getMood() + action.getFavorability());
        }
        reqMyToysVo.setIntimacy(resMyToysVo.getIntimacy() + myToysService.calIntimacy(resMyToysVo, resMyToysVo.getMood()));

        myToysService.updateModel(resMyToysVo);

        redisUtils.batchDel(lastEventKey); //删除存储的事件


        return ResultT.success();
    }

    @Override
    public void handleWorldCountTask() {

        ReqWorldInfoVo reqWorldInfoVo = new ReqWorldInfoVo();
        reqWorldInfoVo.setStatus(2);

        List<ResWorldInfoVo> worldInfoVos = worldInfoService.getModelListByConditions(reqWorldInfoVo);
        if (worldInfoVos == null) {
            return;
        }
        ReqToysVo reqToysVo = new ReqToysVo();
        reqToysVo.setStatus(0);

        List<ResToysVo> toysVoList = toysMapper.getModelListByConditions(reqToysVo);

        if (toysVoList == null) {
            return;
        }
        final Set<String>[] keys = new Set[]{null};
        final String[] worldPrefix = {"world-Store" + ":"};
        String suffix = ":event";
//        ToysWorldServiceImpl proxy = applicationContext.getBean(ToysWorldServiceImpl.class);
        worldInfoVos.forEach(worldInfoVo -> {
            toysVoList.forEach(toysVo -> {
                worldPrefix[0] = worldPrefix[0] + worldInfoVo.getWorldAiId() + ":" + toysVo.getTextChatId();
                keys[0] = redisUtils.getKeysByPrefix(worldPrefix[0]+suffix);
                if (keys[0] == null || keys[0].size() < 10) {
                    for (int i = 0; i < 10 - keys[0].size(); i++) {
                        createAndExecuteTask(worldInfoVo.getWorldAiId(), toysVo.getTextChatId(), worldPrefix[0]+suffix);
                    }
                }
            });
        });
    }

    @Override
    public ResultT eventAccelerate(ReqToysWorldVo reqToysWorldVo) {
        if (StringUtils.isBlank(reqToysWorldVo.getWorldAiId())) {
            return ResultT.fail("世界id不能为空");
        }
        if (reqToysWorldVo.getToysId() == null) {
            return ResultT.fail("崽崽Id不能为空");
        }
        if (reqToysWorldVo.getAudioId() == null) {
            return ResultT.fail("崽崽角色Id不能为空");
        }

        String worldPrefix = "world-Store" + ":" + reqToysWorldVo.getWorldAiId() + ":" + reqToysWorldVo.getAudioId();
        String countDownEventKey = worldPrefix + ":" + "countDownEvent:" + RequestHolder.getUserId();
        redisUtils.batchDel(countDownEventKey); //删除存储的事件

        return ResultT.success();
    }

    @Override
    public ResultT raffle(ReqToysWorldVo reqToysWorldVo) {
        if (StringUtils.isBlank(reqToysWorldVo.getWorldAiId())) {
            return ResultT.fail("世界id不能为空");
        }
        if (reqToysWorldVo.getToysId() == null) {
            return ResultT.fail("崽崽Id不能为空");
        }
        if (reqToysWorldVo.getAudioId() == null) {
            return ResultT.fail("崽崽角色Id不能为空");
        }
        ReqMyToysVo reqMyToysVo = new ReqMyToysVo();
        reqMyToysVo.setId(reqToysWorldVo.getToysId());
        ResMyToysVo resMyToysVo = myToysService.getResModelByConditions(reqMyToysVo);
        if (resMyToysVo == null) {
            return ResultT.fail("崽崽不存在");
        }
        if (resMyToysVo.getIntimacy() != 100) {
            return ResultT.fail("好感度未到100，不能抽奖");
        }
        ReqPrizeInfoVo reqPrizeInfoVo = new ReqPrizeInfoVo();
        reqPrizeInfoVo.setStatus(0);
        List<ResPrizeInfoVo> prizeInfoVoList = prizeInfoService.getModelListByConditions(reqPrizeInfoVo);
        if (CollectionUtils.isEmpty(prizeInfoVoList)) {
            return ResultT.fail("奖品库为空");
        }
        BigDecimal totalWeight = BigDecimal.ZERO;
        for (ResPrizeInfoVo prize : prizeInfoVoList) {
            totalWeight = totalWeight.add(prize.getWinningProbability());
        }
        // 生成随机数
        BigDecimal randomValue = BigDecimal.valueOf(Math.random()).multiply(totalWeight);

        // 确定中奖奖品
        BigDecimal cumulativeWeight = BigDecimal.ZERO;
        ResPrizeInfoVo winningPrize = null;
        for (ResPrizeInfoVo prize : prizeInfoVoList) {
            cumulativeWeight = cumulativeWeight.add(prize.getWinningProbability());
            if (randomValue.compareTo(cumulativeWeight) < 0) {
                winningPrize = prize;
                break;
            }
        }
        // 输出中奖奖品信息
        if (winningPrize != null) {
            log.info("用户：{} ， 中奖： {}",RequestHolder.getUserId(), winningPrize.getPrizeName());
            resMyToysVo.setIntimacy(0);
            myToysService.updateModel(resMyToysVo);
            winningPrize.setRaffleCode(generateUniqueCode());

            ReqWinningRecordVo reqWinningRecordVo = new ReqWinningRecordVo();
            reqWinningRecordVo.setPrizeId(winningPrize.getId());
            reqWinningRecordVo.setUserId(RequestHolder.getUserId());
            reqWinningRecordVo.setStatus(0);
            reqWinningRecordVo.setRaffleCode(winningPrize.getRaffleCode());
            winningRecordService.saveOrUpdate(reqWinningRecordVo);

            return ResultT.success(winningPrize);
        }
        return ResultT.fail("很遗憾，没有中奖");
    }

    public static String generateUniqueCode() {
        // 生成UUID
        UUID uuid = UUID.randomUUID();

        // 将UUID转换为字节数组
        ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
        byteBuffer.putLong(uuid.getMostSignificantBits());
        byteBuffer.putLong(uuid.getLeastSignificantBits());

        // 使用Base64 URL-safe编码将字节数组转换为字符串
        String encoded = Base64.getEncoder().encodeToString(byteBuffer.array());

        // 返回前13位作为唯一编码
        return encoded.substring(0, 13);
    }


    public TTSUtils.Event parseEvent(String jsonString) {
        JSONObject jsonObject = JSONObject.parseObject(jsonString);

        TTSUtils.Event event = new TTSUtils.Event();
        event.setLocation(jsonObject.getString("location"));
        event.setDescription(jsonObject.getString("description"));

        // Parse participants
        List<TTSUtils.Participant> participants = new ArrayList<>();
        JSONArray participantsArray = jsonObject.getJSONArray("participants");
        for (int i = 0; i < participantsArray.size(); i++) {
            JSONObject participantJson = participantsArray.getJSONObject(i);
            TTSUtils.Participant participant = new TTSUtils.Participant();
            participant.setName(participantJson.getString("name"));
            participants.add(participant);
        }
        event.setParticipants(participants);

        // Parse actions_list
        List<TTSUtils.Action> actionsList = new ArrayList<>();
        JSONArray actionsArray = jsonObject.getJSONArray("actions_list");
        for (int i = 0; i < actionsArray.size(); i++) {
            JSONObject actionJson = actionsArray.getJSONObject(i);
            TTSUtils.Action action = new TTSUtils.Action();
            action.setAction(actionJson.getString("action"));
            action.setDes(actionJson.getString("des"));
            action.setFavorability(actionJson.getIntValue("favorability"));
            actionsList.add(action);
        }
        event.setActions_list(actionsList);

        return event;
    }

    @Async("taskExecutor")
    public void createAndExecuteTask(String worldAiId, Integer audioId, String worldPrefix) {
        log.info("createAndExecuteTask-------------");
        try {
            TTSUtils.Event store = ttsUtils.getStoreByWorldIdAndToysAudioId(audioId, worldAiId);
            System.out.println("Store event created: " + store);
            if(store!= null){
                redisUtils.set(worldPrefix + ":" + new Date().getTime(), JSONObject.toJSONString(store), 60 * 60 * 24);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
